package com.btpj.hospital_server.service;

import cn.hutool.core.collection.CollUtil;
import com.btpj.hospital_server.dto.DoctorVisitPlanDTO;
import com.btpj.hospital_server.dto.VisitPlanDTO;
import com.btpj.hospital_server.dto.VisitPlanListDTO;
import com.btpj.hospital_server.dto.VisitPlanResiduesDTO;
import com.btpj.hospital_server.dto.param.VisitPlanParam;
import com.btpj.hospital_server.entity.VisitPlan;
import com.btpj.hospital_server.mapper.VisitPlanMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class VisitPlanService {

    @Resource
    private VisitPlanMapper visitPlanMapper;

    @Resource
    private HospitalDoctorService hospitalDoctorService;

    @Resource
    private HospitalClinicService hospitalClinicService;

    @Resource
    private HospitalInfoService hospitalInfoService;

    @Resource
    private HospitalOutpatientService hospitalOutpatientService;

    @Resource
    private HospitalSpecialService hospitalSpecialService;

    @Resource
    private VisitAppointmentService visitAppointmentService;

    /**
     * 每段时间内 最大就诊人数
     */
    private static final Integer MAX_OF_PATIENTS = 5;

    /**
     * 添加出诊计划
     *
     * @param param VisitPlanParam
     * @return 是否添加成功
     */
    @Transactional
    public boolean addVisitPlan(VisitPlanParam param) {
        VisitPlan visitPlan = new VisitPlan();
        BeanUtils.copyProperties(param, visitPlan);
        return visitPlanMapper.insertSelective(visitPlan) > 0;
    }

    /**
     * 是否存在指定编号的出诊计划
     *
     * @param id 出诊计划编号
     * @return 是否存在指定编号的出诊计划
     */
    public boolean exist(Long id) {
        return visitPlanMapper.selectByPrimaryKey(id) != null;
    }

    /**
     * 更新出诊计划
     *
     * @param id    出诊计划编号
     * @param param VisitPlanParam
     * @return 是否更新成功
     */
    @Transactional
    public boolean updateVisitPlan(Long id, VisitPlanParam param) {
        VisitPlan visitPlan = visitPlanMapper.selectByPrimaryKey(id);
        BeanUtils.copyProperties(param, visitPlan);
        return visitPlanMapper.updateByPrimaryKeySelective(visitPlan) > 0;
    }

    /**
     * 删除出诊计划
     *
     * @param id 出诊计划编号
     * @return 是否删除成功
     */
    public boolean deleteVisitPlan(Long id) {
        return visitPlanMapper.deleteByPrimaryKey(id) > 0;
    }

    /**
     * 批量删除出诊计划
     *
     * @param ids 出诊计划编号集合
     * @return 是否批量删除成功
     */
    public boolean deleteBatch(List<Long> ids) {
        return visitPlanMapper.deleteByPrimaryKeys(ids) > 0;
    }

    /**
     * 查找出诊列表
     *
     * @param hospitalId   医院编号
     * @param specialId    专科编号
     * @param outpatientId 门诊编号
     * @param doctorId     医生编号
     * @param day          出诊日期
     * @return 出诊列表
     */
    public List<VisitPlanDTO> queryList(Long hospitalId, Long specialId, Long outpatientId, Long doctorId, Date day) {
        List<VisitPlan> visitPlans = visitPlanMapper.selectList(hospitalId, specialId, outpatientId, doctorId, day);
        return visitPlans.stream().map(this::convert).collect(Collectors.toList());
    }

    /**
     * 获取医生出诊信息
     *
     * @param doctorId  医生编号
     * @param startDate 开始日期
     * @param endDate   结束日期
     * @return 医生出诊信息
     */
    public DoctorVisitPlanDTO getDoctorPlan(Long doctorId, Date startDate, Date endDate) {
        DoctorVisitPlanDTO doctorVisitPlanDTO = new DoctorVisitPlanDTO();
        doctorVisitPlanDTO.setDoctorDTO(hospitalDoctorService.getDoctorDetail(doctorId));
        List<VisitPlanListDTO> visitPlanListDTOs = new ArrayList<>();
        List<VisitPlan> visitPlans = visitPlanMapper.selectByDoctorIdAndDay(doctorId, startDate, endDate);
        // 用java8的stream处理分类问题
        visitPlans.stream().collect(Collectors.groupingBy(VisitPlan::getHospitalId, Collectors.toList()))
                .forEach((hospitalId, list) -> {
                    VisitPlanListDTO visitPlanListDTO = new VisitPlanListDTO();
                    visitPlanListDTO.setInfo(hospitalInfoService.getHospitalInfo(hospitalId));
                    if (!CollUtil.isEmpty(list)) {
                        visitPlanListDTO.setPlanResiduesDTOList(list.stream()
                                .map(this::covertToResidues)
                                .collect(Collectors.toList()));
                    }
                    visitPlanListDTOs.add(visitPlanListDTO);
                });
        doctorVisitPlanDTO.setPlanListDTOList(visitPlanListDTOs);
        return doctorVisitPlanDTO;
    }


    /**
     * 将VisitPlan转换为出诊计划封装类 VisitPlanDTO
     *
     * @param visitPlan 出诊计划
     * @return 出诊计划封装类
     */
    private VisitPlanDTO convert(VisitPlan visitPlan) {
        VisitPlanDTO visitPlanDTO = new VisitPlanDTO();
        BeanUtils.copyProperties(visitPlan, visitPlanDTO);
        visitPlanDTO.setClinicName(hospitalClinicService.getClinicDetails(visitPlan.getClinicId()).getAddress());
        visitPlanDTO.setDoctorName(hospitalDoctorService.getDoctorDetail(visitPlan.getDoctorId()).getName());
        visitPlanDTO.setHospitalName(hospitalInfoService.getHospitalInfo(visitPlan.getHospitalId()).getName());
        visitPlanDTO.setOutpatientName(hospitalOutpatientService.getOutpatientDetails(visitPlan.getOutpatientId()).getName());
        visitPlanDTO.setSpecialName(hospitalSpecialService.getSpecialDetails(visitPlan.getSpecialId()).getName());
        return visitPlanDTO;
    }

    /**
     * 将VisitPlan转换为出诊计划挂号封装类 VisitPlanResiduesDTO
     *
     * @param visitPlan 出诊计划
     * @return 出诊计划挂号封装类
     */
    private VisitPlanResiduesDTO covertToResidues(VisitPlan visitPlan) {
        VisitPlanResiduesDTO visitPlanResiduesDTO = new VisitPlanResiduesDTO();
        BeanUtils.copyProperties(visitPlan, visitPlanResiduesDTO);
        List<Integer> residueList = new ArrayList<>();
        // 对应VisitAppointment中的timePeriod属性
        for (int i = 1; i < 15; i++) {
            residueList.add(MAX_OF_PATIENTS - visitAppointmentService.getAppointmentNum(visitPlan.getId(), i));
        }
        visitPlanResiduesDTO.setResidues(residueList);
        return visitPlanResiduesDTO;
    }

    /**
     * 获取医生出诊信息
     *
     * @param hospitalId 医院编号
     * @param doctorId   医生编号
     * @param date       日期
     * @return 医生出诊信息
     */
    public List<VisitPlanResiduesDTO> getVisitPlanByHospitalAndDoctorAndDate(Long hospitalId, Long doctorId, Date date) {
        List<VisitPlan> visitPlans = visitPlanMapper.selectList(hospitalId, null, null, doctorId, date);
        if (CollUtil.isEmpty(visitPlans)) {
            return null;
        }
        return visitPlans.stream().map(this::covertToResidues).collect(Collectors.toList());
    }
}
